﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using System.Xml.Linq;
using Rem.Objects;
using System.Data;

namespace FileDB
{

    public partial class Contract : IFileDB
    {
        private string _fileName;

        public string FileName
        {
            get { return _fileName; }
            set { _fileName = value; }
        }


        public decimal TaxRate { get; set; }
    }
    public partial class Contract
    {
        public static string RootDir = "Contracts";
        public static string FullRootDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
            DataManager.DataDir, RootDir);
        private static string MetaDataFileName = "00000000.xml";
        private static string MetaDataFullFileName =
            Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
            DataManager.DataDir, RootDir, MetaDataFileName);

        internal static void CreateDefaultTemplate()
        {
            if (File.Exists(MetaDataFullFileName))
                throw new Exception(string.Format("MetaData file already exists", MetaDataFullFileName));

            XElement metadata =
                new XElement("MetaData", new XAttribute("MaxId", 0.ToString("d8")));
            metadata.Save(MetaDataFullFileName);
        }

        internal static int NextID()
        {
            XDocument xml = XDocument.Load(MetaDataFullFileName);
            return Int32.Parse(xml.Root.Attribute("MaxId").Value) + 1;
        }

        internal static void UpdateMaxId(int nextId)
        {
            XDocument xml = XDocument.Load(MetaDataFullFileName);
            xml.Root.Attribute("MaxId").SetValue(nextId.ToString("d8"));
            xml.Save(MetaDataFullFileName);
        }

        public static string GetFileName(Contract c)
        {
            return GetFileName(c.Id);
        }
        public static string GetFileName(int Id)
        {
            return Path.Combine(FullRootDir,
                string.Format("{0}.xml",
                Id.ToString("d8")));
        }


        public static void Delete(Contract contract)
        {
            Reminder.DeleteContractReminders(contract.Id);
            File.Delete(contract.FileName);
        }
        public static int Insert(Contract contract)
        {
            int id = NextID();
            contract.Id = id;
            Save(contract, GetFileName(id));
            GenerateRinders(contract);

            UpdateMaxId(id);
            return id;
        }

        public static void GenerateRinders(Contract contract)
        {
            Reminder.Insert(new Reminder()
            {
                StartTime = contract.StartDate,
                DueTime = contract.DueDate,
                ReminderTime = contract.DueDate.AddDays(-contract.AdvancedRenew),
                Category = ReminderCategory.RenewReminder,
                ContractId = contract.Id,
                Message = string.Format("门面地址:{0} 租金:{1} {6} 收租方:{2} 缴租方:{3} 上次租期:{4}到{5}",
                    contract.Address, contract.RentPerInterval,
                    contract.CustomerPartA.Name,
                    contract.CustomerPartB.Name,
                    contract.StartDate.Date.ToString("yyyy-MM-dd"),
                    contract.DueDate.Date.ToString("yyyy-MM-dd"), contract.RentUnit)
            });

            var reminder = new Reminder()
            {
                StartTime = contract.StartDate,
                DueTime = contract.DueDate,
                ReminderTime = contract.StartDate.AddDays(-contract.AdvancedDays),
                Status = ReminderState.Actived,
                ContractId = contract.Id,
                Category = ReminderCategory.PostReminder,
                Message = string.Empty,

            };
            // todo:
            if (contract.PartAId == Customer.GetSelfCompany().Id)
            {
                reminder.Category = ReminderCategory.GetReminder;
            }
            //QueryConstants.AdvanceReminderDays, 
            List<Reminder> reminders = Reminder.GeneratePeriodReminder(reminder, contract, 0, contract.RentInterval);
            foreach (var item in reminders)
            {
                Reminder.Insert(item);
            }
        }

        public static void Save(Contract contract)
        {
            //for (int i = 0; i < 1500; i++)
            //{
            //    contract.Id = -1;
            //    Insert(contract);
            //}

            if (contract.Id < 1)
            {
                Insert(contract);
            }
            else
            {
                Save(contract, GetFileName(contract));
            }
        }

        private static void Save(Contract customer, string fileName)
        {
            XElement r =
                new XElement("Contract", new XAttribute("Id", customer.Id),
                    new XElement("Address", customer.Address),
                    new XElement("AdvancedDays", customer.AdvancedDays),
                    new XElement("AdvancedRenew", customer.AdvancedRenew),
                    new XElement("CanTicket", customer.CanTicket),
                    new XElement("Comment", customer.Comment),
                    new XElement("ContractNo", customer.ContractNo),
                    new XElement("Deposit", customer.Deposit),
                    new XElement("DueDate", customer.DueDate.Date),
                    new XElement("EmployeeId", customer.EmployeeId),
                    new XElement("FreeDaysIn", customer.FreeDaysIn),
                    new XElement("FreeDaysOut", customer.FreeDaysOut),
                    new XElement("PartAId", customer.PartAId),
                    new XElement("PartBId", customer.PartBId),
                    new XElement("RentUnit", customer.RentUnit),
                    new XElement("RentInterval", customer.RentInterval),
                    new XElement("RentPerInterval", customer.RentPerInterval),
                    new XElement("SignTime", customer.SignTime.Date),
                    new XElement("StartDate", customer.StartDate.Date),
                    new XElement("Status", customer.Status),
                    new XElement("Width", customer.Width),
                    new XElement("TaxRate", customer.TaxRate)


                    );
            customer.FileName = fileName;
            r.Save(fileName);
        }

        public static List<Contract> GetAllContract()
        {
            List<Contract> customers = new List<Contract>();
            var fileList = Directory.GetFiles(FullRootDir);

            foreach (var fileName in fileList)
            {
                if (fileName != MetaDataFullFileName)
                    customers.Add(GetData(fileName));
            }
            return customers;
        }
        private static Contract GetData(string fileName)
        {

            XDocument xml = XDocument.Load(fileName);
            var data = xml.Root;
            return new Contract()
            {
                Id = Int32.Parse(data.Attribute("Id").Value),

                FileName = fileName,
                Address = data.Element("Address").Value,
                AdvancedDays = Int32.Parse(data.Element("AdvancedDays").Value),
                AdvancedRenew = Int32.Parse(data.Element("AdvancedRenew").Value),
                CanTicket = bool.Parse(data.Element("CanTicket").Value),
                Comment = data.Element("Comment").Value,
                ContractNo = data.Element("ContractNo").Value,
                Deposit = double.Parse(data.Element("Deposit").Value),
                DueDate = DateTime.Parse(data.Element("DueDate").Value),
                EmployeeId = Int32.Parse(data.Element("EmployeeId").Value),
                FreeDaysIn = Int32.Parse(data.Element("FreeDaysIn").Value),
                FreeDaysOut = Int32.Parse(data.Element("FreeDaysOut").Value),
                PartAId = Int32.Parse(data.Element("PartAId").Value),
                PartBId = Int32.Parse(data.Element("PartBId").Value),
                //TotalRent = Double.Parse(data.Element("Rent").Value),
                RentInterval = Int32.Parse(data.Element("RentInterval").Value),
                RentPerInterval = Double.Parse(data.Element("RentPerInterval").Value),
                SignTime = DateTime.Parse(data.Element("SignTime").Value),
                StartDate = DateTime.Parse(data.Element("StartDate").Value),
                Status = data.Element("Status").Value,
                Width = decimal.Parse(data.Element("Width").Value),
                RentUnit = data.Element("RentUnit").Value,
                TaxRate = decimal.Parse(data.Element("TaxRate").Value)

            };

        }
        //rent should get or post in this year already.
        public double GetRentInThisYearForSignalContract()
        {
            if (this.Id < 1)
                return 0.0;
            var reminder = new Reminder()
            {
                StartTime = this.StartDate,
                DueTime = this.DueDate,
                ReminderTime = this.StartDate.AddDays(-this.AdvancedDays),
                Status = ReminderState.Actived,
                ContractId = this.Id,
                Category = ReminderCategory.PostReminder,
                Message = string.Empty,

            };
            // todo:
            if (this.PartAId == Customer.GetSelfCompany().Id)
            {
                reminder.Category = ReminderCategory.GetReminder;
            }
            var reminderList = Reminder.GeneratePeriodReminder(reminder, this, 0, this.RentInterval);

            return (from rr in reminderList
                    where rr.DueTime >= DateTime.Now.Date
                    && rr.StartTime <= DateTime.Now.Date
                    select rr.RelatedRent).Sum();
        }

        //rent should get or post in this year already.
        public static DataView GetAllRentInThisMonth(int year, out double getInThisMonth, out double postInThisMonth,
            out double getInThisYear, out double postInThisYear)
        {
            getInThisMonth = 0.0;
            postInThisMonth = 0.0;
            getInThisYear = 0.0;
            postInThisYear = 0.0;
            List<Contract> contractList =
                (from contract in
                     Contract.GetAllContract()
                 where contract.Status == ReminderState.Actived
                 && contract.DueDate.Date >= new DateTime(year, 1, 1).Date
                 select contract).ToList();

            Dictionary<int, Tuple<double, double>> monthInYear = new Dictionary<int, Tuple<double, double>>();

            foreach (var c in contractList)
            {
                var reminder = new Reminder()
                {
                    StartTime = c.StartDate,
                    DueTime = c.DueDate,
                    ReminderTime = c.StartDate.AddDays(-c.AdvancedDays),
                    Status = ReminderState.Actived,
                    ContractId = c.Id,
                    Category = ReminderCategory.PostReminder,
                    Message = string.Empty,

                };

                if (c.PartAId == Customer.GetSelfCompany().Id)
                {
                    reminder.Category = ReminderCategory.GetReminder;
                }
                var reminderList = Reminder.GeneratePeriodReminder(reminder, c, 0, c.RentInterval);

                //double v = (from rr in reminderList
                //            where rr.ReminderTime >=
                //            (new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1)).Date
                //            && rr.ReminderTime <
                //            (new DateTime(DateTime.Now.Year, (DateTime.Now.AddMonths(1)).Month, 1)).Date
                //            select rr.RelatedRent).Sum();

                //double u = (from rr in reminderList
                //            where rr.ReminderTime >=
                //            (new DateTime(DateTime.Now.Year, 1, 1)).Date
                //            && rr.ReminderTime < (new DateTime(DateTime.Now.Year + 1, 1, 1)).Date
                //            select rr.RelatedRent).Sum();

                //if (reminder.Category == ReminderCategory.GetReminder)
                //{
                //    getInThisMonth += v;
                //    getInThisYear += u;

                //}
                //else if (reminder.Category == ReminderCategory.PostReminder)
                //{
                //    postInThisMonth += v;
                //    postInThisYear += u;
                //}

                foreach (var item in (from rr in reminderList
                                      where rr.ReminderTime >=
                                      (new DateTime(year, 1, 1)).Date
                                      && rr.ReminderTime <
                                      (new DateTime(year + 1, 1, 1)).Date
                                      select rr).ToList())
                {
                    if (!monthInYear.ContainsKey(item.ReminderTime.Month))
                    {
                        monthInYear.Add(item.ReminderTime.Month, new Tuple<double, double>(0.0, 0.0));
                    }

                    if (item.Category == ReminderCategory.GetReminder)
                    {
                        monthInYear[item.ReminderTime.Month] = new Tuple<double, double>
                            (
                            item.RelatedRent + monthInYear[item.ReminderTime.Month].Item1,
                            monthInYear[item.ReminderTime.Month].Item2
                            );
                        getInThisYear += item.RelatedRent;
                    }
                    else if (reminder.Category == ReminderCategory.PostReminder)
                    {
                        monthInYear[item.ReminderTime.Month] = new Tuple<double, double>
                            (
                            monthInYear[item.ReminderTime.Month].Item1,
                            item.RelatedRent + monthInYear[item.ReminderTime.Month].Item2
                            );

                        postInThisYear += item.RelatedRent;
                    }
                }

            }

            if (monthInYear.ContainsKey(DateTime.Now.Month))
            {
                getInThisMonth = monthInYear[DateTime.Now.Month].Item1;
                postInThisMonth = monthInYear[DateTime.Now.Month].Item2;
            }

            DataTable dt = new DataTable();
            dt.Columns.Add("month", typeof(string));
            dt.Columns.Add("get", typeof(string));
            dt.Columns.Add("post", typeof(string));
            foreach (var item in monthInYear)
            {
                DataRow dr = dt.NewRow();
                dr["month"] = string.Format("{0}-{1}", year, item.Key.ToString("00"));
                dr["get"] = item.Value.Item1.ToString("###,###,##0");
                dr["post"] = item.Value.Item2.ToString("###,###,##0");
                dt.Rows.Add(dr);
            }

            return dt.AsDataView();
        }


        public static List<Reminder> GetReminders(int year, int month, bool forGetting)
        {
            List<Reminder> reminders = new List<Reminder>();
            List<Contract> contractList =
                (from contract in
                     Contract.GetAllContract()
                 where contract.Status == ReminderState.Actived
                 && contract.DueDate.Date >= new DateTime(year, month, 1).Date
                 select contract).ToList();

            Dictionary<int, Tuple<double, double>> monthInYear = new Dictionary<int, Tuple<double, double>>();

            foreach (var c in contractList)
            {
                if (forGetting && (c.PartAId != Customer.GetSelfCompany().Id))
                {
                    continue;
                }

                if (!forGetting && (c.PartBId != Customer.GetSelfCompany().Id))
                {
                    continue;
                }

                var tempReminders = (from rr in c.Reminders
                                     where rr.ReminderTime >=
                                     (new DateTime(year, month, 1)).Date
                                     && rr.ReminderTime <
                                     (new DateTime(year, month, 1)).AddMonths(1).Date
                                     select rr).ToList();

                reminders.AddRange(tempReminders);
            }
            return reminders;
        }
    }
}
